﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Xml;
using Common.Utilities;
using Common.Utilities.Dispatcher;

namespace Workflows.Components.Entities.Relations.InferredAssociations
{
    [Serializable]
    public class ClusteringInstruction:InstructionBase
    {
        #region props
        #region src
        private string _EntityPartitionFilePath;
        /// <summary></summary>
        public string EntityPartitionFilePath
        {
            get
            {
                return this._EntityPartitionFilePath;
            }
            set
            {
                this._EntityPartitionFilePath = value;
            }
        }

        private DataProviderType _DbProvider;
        /// <summary></summary>
        public DataProviderType DbProvider
        {
            get
            {
                return this._DbProvider;
            }
            set
            {
                this._DbProvider = value;
            }
        }

        private string _ConnStr;
        /// <summary></summary>
        public string ConnStr
        {
            get
            {
                return this._ConnStr;
            }
            set
            {
                this._ConnStr = value;
            }
        }

        private string _SelectSql;
        /// <summary></summary>
        public string SelectSql
        {
            get
            {
                return this._SelectSql;
            }
            set
            {
                this._SelectSql = value;
            }
        }

        private string _EntityIDFieldName;
        /// <summary></summary>
        public string EntityIDFieldName
        {
            get
            {
                return this._EntityIDFieldName;
            }
            set
            {
                this._EntityIDFieldName = value;
            }
        }
        #endregion

        #region comparer
        private List<AttributeMetaData> _ComparableAttributeMetaDatas;
        /// <summary></summary>
        public List<AttributeMetaData> ComparableAttributeMetaDatas
        {
            get
            {
                return this._ComparableAttributeMetaDatas;
            }
            set
            {
                this._ComparableAttributeMetaDatas = value;
            }
        }
        #endregion

        #region cluster settings
        private string _ClusterCalculatorAssemblyFileName;
        /// <summary></summary>
        public string ClusterCalculatorAssemblyFileName
        {
            get
            {
                return this._ClusterCalculatorAssemblyFileName;
            }
            set
            {
                this._ClusterCalculatorAssemblyFileName = value;
            }
        }

        private string _ClusterCalculatorTypeName;
        /// <summary></summary>
        public string ClusterCalculatorTypeName
        {
            get
            {
                return this._ClusterCalculatorTypeName;
            }
            set
            {
                this._ClusterCalculatorTypeName = value;
            }
        }

        private double _EntityMembershipThreshold;
        /// <summary></summary>
        public double EntityMembershipThreshold
        {
            get
            {
                return this._EntityMembershipThreshold;
            }
            set
            {
                this._EntityMembershipThreshold = value;
            }
        }

        private double _ClusterDiameterThreshold;
        /// <summary></summary>
        public double ClusterDiameterThreshold
        {
            get
            {
                return this._ClusterDiameterThreshold;
            }
            set
            {
                this._ClusterDiameterThreshold = value;
            }
        }

        private int _ClusterSizeThreshold;
        /// <summary></summary>
        public int ClusterSizeThreshold
        {
            get
            {
                return this._ClusterSizeThreshold;
            }
            set
            {
                this._ClusterSizeThreshold = value;
            }
        }

        private double _ClusterFuzziness;
        /// <summary></summary>
        public double ClusterFuzziness
        {
            get
            {
                return this._ClusterFuzziness;
            }
            set
            {
                this._ClusterFuzziness = value;
            }
        }
        #endregion

        #region target
        private DataProviderType _TgtDbProvider;
        /// <summary></summary>
        public DataProviderType TgtDbProvider
        {
            get
            {
                return this._TgtDbProvider;
            }
            set
            {
                this._TgtDbProvider = value;
            }
        }

        private string _TgtConnStr;
        /// <summary></summary>
        public string TgtConnStr
        {
            get
            {
                return this._TgtConnStr;
            }
            set
            {
                this._TgtConnStr = value;
            }
        }

        private string _ClusterInstanceTableName;
        /// <summary></summary>
        public string ClusterInstanceTableName
        {
            get
            {
                return this._ClusterInstanceTableName;
            }
            set
            {
                this._ClusterInstanceTableName = value;
            }
        }

        private string _ClusterInstanceClusterIDFieldName;
        /// <summary></summary>
        public string ClusterInstanceClusterIDFieldName
        {
            get
            {
                return this._ClusterInstanceClusterIDFieldName;
            }
            set
            {
                this._ClusterInstanceClusterIDFieldName = value;
            }
        }

        private Dictionary<string,string> _ClusterInstanceFieldMappings;
        /// <summary></summary>
        public Dictionary<string,string> ClusterInstanceFieldMappings
        {
            get
            {
                return this._ClusterInstanceFieldMappings;
            }
            set
            {
                this._ClusterInstanceFieldMappings = value;
            }
        }

        private string _ClusterMembershipTableName;
        /// <summary></summary>
        public string ClusterMembershipTableName
        {
            get
            {
                return this._ClusterMembershipTableName;
            }
            set
            {
                this._ClusterMembershipTableName = value;
            }
        }

        private string _ClusterMemberClusterIDFieldName;
        /// <summary></summary>
        public string ClusterMemberClusterIDFieldName
        {
            get
            {
                return this._ClusterMemberClusterIDFieldName;
            }
            set
            {
                this._ClusterMemberClusterIDFieldName = value;
            }
        }

        private string _ClusterMemberEntityIDFieldName;
        /// <summary></summary>
        public string ClusterMemberEntityIDFieldName
        {
            get
            {
                return this._ClusterMemberEntityIDFieldName;
            }
            set
            {
                this._ClusterMemberEntityIDFieldName = value;
            }
        }

        private string _ClusterMemberScoreFieldName;
        /// <summary></summary>
        public string ClusterMemberScoreFieldName
        {
            get
            {
                return this._ClusterMemberScoreFieldName;
            }
            set
            {
                this._ClusterMemberScoreFieldName = value;
            }
        }

        private string _ClusterMemberMembershipFieldName;
        /// <summary></summary>
        public string ClusterMemberMembershipFieldName
        {
            get
            {
                return this._ClusterMemberMembershipFieldName;
            }
            set
            {
                this._ClusterMemberMembershipFieldName = value;
            }
        }
        #endregion
        #endregion

        #region ctor
        public ClusteringInstruction():base(Guid.Empty,Guid.Empty)
        {
            this._EntityPartitionFilePath = string.Empty;
            this._DbProvider = DataProviderType.MSSQL;
            this._ConnStr = string.Empty;
            this._SelectSql = string.Empty;
            this._EntityIDFieldName = string.Empty;

            this._ComparableAttributeMetaDatas = new List<AttributeMetaData>();

            this._ClusterCalculatorAssemblyFileName = string.Empty;
            this._ClusterCalculatorTypeName = string.Empty;
            this._EntityMembershipThreshold = 0.5;
            this._ClusterSizeThreshold = int.MaxValue;
            this._ClusterDiameterThreshold = double.PositiveInfinity;
            this._ClusterFuzziness = 2;

            this._TgtDbProvider = DataProviderType.MSSQL;
            this._TgtConnStr = string.Empty;
            this._ClusterInstanceTableName = string.Empty;
            this._ClusterInstanceClusterIDFieldName = string.Empty;
            this._ClusterInstanceFieldMappings = new Dictionary<string, string>();
            this._ClusterMembershipTableName = string.Empty;
            this._ClusterMemberClusterIDFieldName = string.Empty;
            this._ClusterMemberEntityIDFieldName = string.Empty;
            this._ClusterMembershipTableName = string.Empty;
            this._ClusterMemberMembershipFieldName = string.Empty;
        }

        public ClusteringInstruction(Guid componentID, Guid jobTicketID,
            string partitionFilePath, DataProviderType dbProvider, 
            string connStr, string selectSql, string idField,
            List<AttributeMetaData> attrMetaDatas,
            string clusterAssemblyName,
            string clusterTypeName,
            double membershipThreshold,
            int clusterSizeThreshold,
            double clusterDiameterThreshold,
            double fuzziness,
            DataProviderType tgtDbProvider,
            string tgtConnStr,
            string instanceTbl,
            string instanceClusterIDField,
            Dictionary<string,string> instanceTableFieldMappings,
            string memberTbl, 
            string memberClusterIDField,
            string memberEntityIDField,
            string memberScoreField,
            string memberMembershipField) 
            : base(componentID, jobTicketID)
        {
            this._EntityPartitionFilePath = partitionFilePath;
            this._DbProvider = dbProvider;
            this._ConnStr = connStr;
            this._SelectSql = selectSql;
            this._EntityIDFieldName = idField;

            this._ComparableAttributeMetaDatas = attrMetaDatas;

            this._ClusterCalculatorAssemblyFileName = clusterAssemblyName;
            this._ClusterCalculatorTypeName = clusterTypeName;
            this._ClusterDiameterThreshold = clusterDiameterThreshold;
            this._ClusterSizeThreshold = clusterSizeThreshold;
            this._EntityMembershipThreshold = membershipThreshold;
            this._ClusterDiameterThreshold = clusterDiameterThreshold;
            this._ClusterFuzziness = fuzziness;

            this._TgtDbProvider = tgtDbProvider;
            this._TgtConnStr = tgtConnStr;
            this._ClusterInstanceTableName = instanceTbl;
            this._ClusterInstanceClusterIDFieldName = instanceClusterIDField;
            this._ClusterInstanceFieldMappings = instanceTableFieldMappings;
            this._ClusterMembershipTableName = memberTbl;
            this._ClusterMemberClusterIDFieldName = memberClusterIDField;
            this._ClusterMemberEntityIDFieldName = memberEntityIDField;
            this._ClusterMemberScoreFieldName = memberScoreField;
            this._ClusterMemberMembershipFieldName = memberMembershipField;
        }
        #endregion

        public override InstructionBase Instantiate(XmlNode xNode)
        {
            if (xNode.Attributes.GetNamedItem("Type").Value == this.GetType().FullName)
            {
                ClusteringInstruction instruction = new ClusteringInstruction();
                instruction.OwnerComponentID = new Guid(xNode.Attributes.GetNamedItem("ComponentID").Value);
                instruction.OwnerWorkerInstanceID = new Guid(xNode.Attributes.GetNamedItem("WorkerID").Value);
                instruction.SubmitTime = DateTime.Parse(xNode.Attributes.GetNamedItem("SubmitTime").Value);
                instruction.StartTime = DateTime.Parse(xNode.Attributes.GetNamedItem("StartTime").Value);

                // data source
                instruction.EntityPartitionFilePath = XmlDataUtil.GetAttributeValue(xNode, "EntityPartitionFilePath", "");
                instruction.DbProvider =
                    (DataProviderType)
                    int.Parse(XmlDataUtil.GetAttributeValue(xNode, "DbProvider",
                                                            ((int) DataProviderType.MSSQL).ToString()));
                instruction.ConnStr = XmlDataUtil.GetAttributeValue(xNode, "ConnStr", "");
                instruction.SelectSql = XmlDataUtil.GetAttributeValue(xNode, "SelectSql", "");
                instruction.EntityIDFieldName = XmlDataUtil.GetAttributeValue(xNode, "EntityIDFieldName", "");

                // attributes
                XmlNodeList attributeNodes = xNode.SelectNodes("Attributes/Attribute");
                if(attributeNodes != null && attributeNodes.Count>0)
                {
                    instruction.ComparableAttributeMetaDatas = new List<AttributeMetaData>();
                    foreach(XmlNode attrNode in attributeNodes)
                    {
                        string assemblyName = XmlDataUtil.GetAttributeValue(attrNode, "AssemblyName", "");
                        string typeNmae = XmlDataUtil.GetAttributeValue(attrNode, "TypeName", "");
                        AttributeType attrType =
                            (AttributeType)
                            int.Parse(XmlDataUtil.GetAttributeValue(attrNode, "AttributeType",
                                                                    ((int)AttributeType.NativeAttribute).ToString()));
                        double posW = double.Parse(XmlDataUtil.GetAttributeValue(attrNode, "PositiveWeight", "1.0"));
                        double negW = double.Parse(XmlDataUtil.GetAttributeValue(attrNode, "NegativeWeight", "-1.0"));
                        bool isExternalAttr =
                            bool.Parse(XmlDataUtil.GetAttributeValue(attrNode, "IsExternal", false.ToString()));
                        DataProviderType extDbProvider =
                            (DataProviderType)
                            int.Parse(XmlDataUtil.GetAttributeValue(attrNode, "ExtDbProvider",
                                                                    ((int)DataProviderType.MSSQL).ToString()));
                        string extConnStr = XmlDataUtil.GetAttributeValue(attrNode, "ExtConnStr", "");
                        string extSql = XmlDataUtil.GetAttributeValue(attrNode, "ExtSql", "");

                        Dictionary<string, string> comparerSettings = new Dictionary<string, string>();
                        XmlNodeList settingNodes = attrNode.SelectNodes("Setting");
                        if (settingNodes != null && settingNodes.Count > 0)
                        {
                            foreach (XmlNode settingNode in settingNodes)
                            {
                                string name = XmlDataUtil.GetAttributeValue(settingNode, "Name", "");
                                string value = XmlDataUtil.GetAttributeValue(settingNode, "Value", "");
                                comparerSettings.Add(name, value);
                            }
                        }

                        if(attrType==AttributeType.CompositeAttribute)
                        {
                            Dictionary<string, string> argAttrBindings = new Dictionary<string, string>();
                            XmlNodeList attrNameNodes = attrNode.SelectNodes("Attribute");
                            foreach(XmlNode attrNameNode in attrNameNodes)
                            {
                                string argName = XmlDataUtil.GetAttributeValue(attrNameNode, "ArgumentName", "");
                                string attrName = XmlDataUtil.GetAttributeValue(attrNameNode, "AttributeName", "");
                                argAttrBindings.Add(argName, attrName);
                            }
                            
                            AttributeMetaData attrMetaData = new AttributeMetaData(
                                argAttrBindings, assemblyName, typeNmae, 
                                comparerSettings, posW, negW,
                                isExternalAttr, extDbProvider, extConnStr, extSql);
                            instruction.ComparableAttributeMetaDatas.Add(attrMetaData);
                        }
                        else
                        {
                            string attrName = XmlDataUtil.GetAttributeValue(attrNode, "AttributeName", "");
                            AttributeMetaData attrMetaData = new AttributeMetaData(
                                attrName, attrType, assemblyName, typeNmae, 
                                comparerSettings, posW, negW,
                                isExternalAttr, extDbProvider, extConnStr, extSql);
                            instruction.ComparableAttributeMetaDatas.Add(attrMetaData);
                        }
                    }
                }

                // cluster 
                instruction.ClusterCalculatorAssemblyFileName =
                    XmlDataUtil.GetAttributeValue(xNode, "ClusterCalcAssemblyName", "");
                instruction.ClusterCalculatorTypeName =
                    XmlDataUtil.GetAttributeValue(xNode, "ClusterCalcTypeName", "");
                instruction.ClusterDiameterThreshold = double.Parse(
                    XmlDataUtil.GetAttributeValue(xNode, "ClusterDiameterThreshold", double.PositiveInfinity.ToString()));
                instruction.ClusterSizeThreshold = int.Parse(
                    XmlDataUtil.GetAttributeValue(xNode, "ClusterSizeThreshold", int.MaxValue.ToString()));
                instruction.EntityMembershipThreshold = double.Parse(
                    XmlDataUtil.GetAttributeValue(xNode, "MembershipThreshold", "0.5"));
                instruction.ClusterFuzziness = double.Parse(
                    XmlDataUtil.GetAttributeValue(xNode, "Fuzziness", "2.0"));

                // tgt 
                instruction.TgtDbProvider =
                    (DataProviderType) int.Parse(
                                           XmlDataUtil.GetAttributeValue(
                                               xNode, "TgtDbProvider", ((int) DataProviderType.MSSQL).ToString()));
                instruction.TgtConnStr = XmlDataUtil.GetAttributeValue(xNode, "TgtConnStr", "");
                instruction.ClusterInstanceTableName = XmlDataUtil.GetAttributeValue(xNode, "InstanceTable", "");
                instruction.ClusterInstanceClusterIDFieldName =
                    XmlDataUtil.GetAttributeValue(xNode, "InstanceClusterIDFieldName", "");
                XmlNodeList fieldMappingNodes = xNode.SelectNodes("InstanceFieldMappings/FieldMapping");
                if(fieldMappingNodes !=null && fieldMappingNodes.Count>0)
                {
                    instruction.ClusterInstanceFieldMappings = new Dictionary<string, string>();
                    foreach(XmlNode mappingNode in fieldMappingNodes)
                    {
                        string srcFieldName = XmlDataUtil.GetAttributeValue(mappingNode, "SrcField", "");
                        string tgtFieldName = XmlDataUtil.GetAttributeValue(mappingNode, "TgtField", "");
                        instruction.ClusterInstanceFieldMappings.Add(srcFieldName,tgtFieldName);
                    }
                }
                instruction.ClusterMembershipTableName = XmlDataUtil.GetAttributeValue(xNode, "MemberTable", "");
                instruction.ClusterMemberClusterIDFieldName = 
                    XmlDataUtil.GetAttributeValue(xNode, "MemberClusterIDField", "");
                instruction.ClusterMemberEntityIDFieldName = 
                    XmlDataUtil.GetAttributeValue(xNode, "MemberEntityIDField", "");
                instruction.ClusterMemberScoreFieldName =
                    XmlDataUtil.GetAttributeValue(xNode, "MemberScoreField", "");
                instruction.ClusterMemberMembershipFieldName =
                    XmlDataUtil.GetAttributeValue(xNode, "MemberMembershipField", "");

                return instruction;
            }
            else
            {
                throw new Exception("Unable to instantiate instruction: invalid type specified in xml node");
            }
        }

        public override XmlNode Serialize(ref XmlDocument xDoc, ref XmlNode parentNode)
        {
            XmlNode xNode = XmlDataUtil.AddElement(ref xDoc, parentNode, "Instruction");
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "Type", this.GetType().FullName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ComponentID", this.OwnerComponentID.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "WorkerID", this.OwnerWorkerInstanceID.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SubmitTime", this.SubmitTime.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "StartTime", this.StartTime.ToString());

            // src
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode,"EntityPartitionFilePath",this.EntityPartitionFilePath);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "DbProvider", ((int)this.DbProvider).ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ConnStr",this.ConnStr);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode,"SelectSql",this.SelectSql);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "EntityIDFieldName",this.EntityIDFieldName);

            // comparers 
            if (this.ComparableAttributeMetaDatas != null && this.ComparableAttributeMetaDatas.Count>0)
            {
                XmlNode attrRootNode = XmlDataUtil.AddElement(ref xDoc, xNode, "Attributes");
                foreach (AttributeMetaData attributeMetaData in this.ComparableAttributeMetaDatas)
                {
                    XmlNode attrNode = XmlDataUtil.AddElement(ref xDoc, attrRootNode, "Attribute");
                    XmlDataUtil.UpdateAttribute(ref xDoc, attrNode, "AssemblyName", attributeMetaData.ComparerAssemblyName);
                    XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "TypeName", attributeMetaData.ComparerTypeName);
                    XmlDataUtil.UpdateAttribute(ref xDoc, attrNode, "AttributeType",
                                                ((int) attributeMetaData.AttributeType).ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, attrNode, "PositiveWeight", attributeMetaData.PositiveMatchWeight.ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, attrNode, "NegativeWeight", attributeMetaData.NegativeMatchWeight.ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, attrNode, "IsExternal", attributeMetaData.IsExternalAttribute.ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, attrNode, "ExtDbProvider", ((int)attributeMetaData.ExternalAttributeDbProvider).ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, attrNode, "ExtConnStr", attributeMetaData.ExternalAttributeConnStr);
                    XmlDataUtil.UpdateAttribute(ref xDoc, attrNode, "ExtSql", attributeMetaData.ExternalAttributeSelectSql);


                    if (attributeMetaData.ComparerSettings != null && attributeMetaData.ComparerSettings.Count > 0)
                    {
                        foreach (string name in attributeMetaData.ComparerSettings.Keys)
                        {
                            XmlNode settingNode = XmlDataUtil.AddElement(ref xDoc, attrNode, "Setting");
                            XmlDataUtil.UpdateAttribute(ref xDoc, settingNode, "Name", name);
                            XmlDataUtil.UpdateAttribute(ref xDoc, settingNode, "Value", attributeMetaData.ComparerSettings[name]);
                        }
                    }

                    if(attributeMetaData.AttributeType==AttributeType.CompositeAttribute)
                    {
                        
                        foreach(string argName in attributeMetaData.ArgNameAttrNameBindings.Keys)
                        {
                            XmlNode attrNameNode = XmlDataUtil.AddElement(ref xDoc, attrNode, "Attribute");
                            XmlDataUtil.UpdateAttribute(ref xDoc, attrNameNode, "ArgumentName",argName);
                            XmlDataUtil.UpdateAttribute(ref xDoc, attrNameNode, "AttributeName",
                                                        attributeMetaData.ArgNameAttrNameBindings[argName]);
                        }
                    }
                    else
                    {
                        XmlDataUtil.UpdateAttribute(ref xDoc, attrNode,"AttributeName",attributeMetaData.AttributeName);
                    }
                }
            }

            // cluster 
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ClusterCalcAssemblyName",
                                        this.ClusterCalculatorAssemblyFileName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ClusterCalcTypeName",this.ClusterCalculatorTypeName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ClusterDiameterThreshold",
                                        this.ClusterDiameterThreshold.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ClusterSizeThreshold", this.ClusterSizeThreshold.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "MembershipThreshold",
                                        this.EntityMembershipThreshold.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "Fuzziness", this.ClusterFuzziness.ToString());

            // tgt 
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "TgtDbProvider", ((int) this.TgtDbProvider).ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode,"TgtConnStr", this.TgtConnStr);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "InstanceTable",this.ClusterInstanceTableName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "InstanceClusterIDField", this.ClusterInstanceClusterIDFieldName);
            if(this.ClusterInstanceFieldMappings!=null && this.ClusterInstanceFieldMappings.Count>0)
            {
                XmlNode fieldMappingRootNode = XmlDataUtil.AddElement(ref xDoc, xNode, "InstanceFieldMappings");
                foreach(string srcField in this.ClusterInstanceFieldMappings.Keys)
                {
                    XmlNode fieldMappingNode = XmlDataUtil.AddElement(ref xDoc, fieldMappingRootNode, "FieldMapping");
                    XmlDataUtil.UpdateAttribute(ref xDoc, fieldMappingNode, "SrcField",srcField);
                    XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "TgtField",this.ClusterInstanceFieldMappings[srcField]);
                }
            }
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode,"MemberTable",this.ClusterMembershipTableName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode,"MemberClusterIDField",this.ClusterMemberClusterIDFieldName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode,"MemberEntityIDField",this.ClusterMemberEntityIDFieldName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "MemberScoreField",this.ClusterMemberScoreFieldName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "MemberMembershipField",this.ClusterMemberMembershipFieldName);

            return xNode;
        }
    }
}
